package com.mrper.asm.click

import org.objectweb.asm.Opcodes
import org.objectweb.asm.Type

object ViewClickRecordPool {

    /** Lambda点击方法的查找库 **/
    val clickLambdaMethodLookup: MutableList<ClickMethodTagInfo> = mutableListOf()

    /**
     * 判断是否是点击方法
     * @param name 方法名称
     * @param desc 方法描述
     * @param access 方法修饰符
     */
    fun isClickMethod(name: String?, desc: String?, access: Int): Boolean {
        return !name.isNullOrEmpty()
            && !desc.isNullOrEmpty()
            && access.and(Opcodes.ACC_PUBLIC) == Opcodes.ACC_PUBLIC
            && name == ViewClickMethodConstants.ViewOnClickMethodName
            && desc == ViewClickMethodConstants.ViewOnClickMethodDescriptor
    }

    /**
     * 查找满足条件的方法
     * 范例：onCreateView$lambda$0, (Ljava/lang/Object;Landroid/view/View;)V
     * @param name 方法名，onCreateView$lambda$0
     * @param desc 方法描述 (Ljava/lang/Object;Landroid/view/View;)V
     * @param access 方法修饰符 ACC_PRIVATE, ACC_STATIC
     * @param lookup 方法查询标记，看该方法是否已经被lambda标记过
     */
    fun isClickLambdaMethod(name: String?, desc: String?, access: Int, lookup: List<ClickMethodTagInfo>): Boolean {
        if (name.isNullOrEmpty() || desc.isNullOrEmpty()) return false
        val returnType = Type.getReturnType(desc)
        val methodArgTypes = Type.getArgumentTypes(desc)
        return (
            access.and(Opcodes.ACC_PRIVATE) == Opcodes.ACC_PRIVATE //lambda调用的方法一定是一个私有方法
                && access.and(Opcodes.ACC_STATIC) == Opcodes.ACC_STATIC //lambda调用的方法一定是一个静态方法
                && returnType == Type.VOID_TYPE // //lambda调用的方法的返回值是个Void对象
                && methodArgTypes.lastOrNull()?.descriptor == ViewClickMethodConstants.ViewDescriptor //方法参数的匹配,最后一个一定是View对象
                && lookup.any { name.matches("${it.anchorMethodName}\\\$lambda\\\$\\d+".toRegex()) }
            ) //表示满足Lambda方法命名的匹配
    }

}